package control;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

import view.GraphicView;

import model.LCS_branch_and_bound;
import model.LCS_divide_conquer;
import model.LCS_dynamic;
import model.LCS_dynamic_approx;
import model.LCS_greedy;
import model.LCS_recursion;
import model.MemoryThread;
import model.Result;
import model.StringFactory;
import model.Tools;

public class Control {
	public static void launch(int choice, Boolean[] lcsList, String arg1,
			String arg2) {
		ArrayList<Result> results = new ArrayList<Result>();
		// Problem
		String a = "";
		String b = "";

		Scanner sc = new Scanner(System.in);
		// a="teslksbnvbjbnkhgg";
		// b="khsvedtesjsefgkq";

		// drawMenu();
		//
		// int choice = sc.nextInt();
		// sc.nextLine();

		switch (choice) {
		case 1:
			a = arg1;
			b = arg2;
			results = testLCS(a, b, lcsList);
			break;
		case 2:
			a = StringFactory.getAleaString(Integer.parseInt(arg1));
			b = StringFactory.getAleaString(Integer.parseInt(arg1));
			results = testLCS(a, b, lcsList);
			break;
		case 3:
			int sLenM = Integer.parseInt(arg1);
			for (int len = 1; len <= sLenM; len++) {
				a = StringFactory.getAleaString(len);
				b = StringFactory.getAleaString(len);
				results.addAll(testLCS(a, b, lcsList));
			}

			break;
		case 4:
			a = StringFactory.getAleaProtein();
			b = StringFactory.getAleaProtein();
			// System.out.print(a);
			// System.out.print(b);
			results = testLCS(a, b, lcsList);
			break;

		case 5:
			a = StringFactory.getAleaWord();
			b = StringFactory.getAleaWord();
			// System.out.print(a);
			// System.out.print(b);
			results = testLCS(a, b, lcsList);
			break;
		case 6:
			int sLenW = Integer.parseInt(arg1);
			for (int len = 1; len <= sLenW; len++) {
				a = StringFactory.getAleaWords(len);
				b = StringFactory.getAleaWords(len);
				results.addAll(testLCS(a, b, lcsList));
			}
			break;
		}

		GraphicView g=new GraphicView(results); 
		drawResults(results);
		saveResults(results);

	}

	public static ArrayList<Result> testLCS(String a, String b,
			Boolean[] lcsList) {

		// Declarations
		ArrayList<Result> results = new ArrayList<Result>();
		long startTime, endTime, duration, space;
		String solution;
		MemoryThread thread = new MemoryThread();
		int i = 0;

		// Thread activation
		thread.start();
		if (lcsList[i]) {
			// Dynamic algorithm
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic.lcs(a, b);
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic", a, b, solution, duration, space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic approx algorithm
			thread.reset();
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic_approx.lcs(a, b, 1);
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Approx 1", a, b, solution,
					duration, space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic approx algorithm
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic_approx.lcs(a, b, 3);
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Approx 3", a, b, solution,
					duration, space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic approx algorithm
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic_approx.lcs(a, b, 10);
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Approx 10", a, b, solution,
					duration, space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic algorithm on simplified problem
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic.lcs(Tools.SimplifyByFreq(a, 5),
					Tools.SimplifyByFreq(b, 5));
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Freq > 5",  a, b, solution, duration,
					space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic algorithm on simplified problem
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic.lcs(Tools.SimplifyByFreq(a, 10),
					Tools.SimplifyByFreq(b, 10));
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Freq > 10", a, b, solution, duration,
					space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic algorithm on simplified problem
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic.lcs(Tools.SimplifyByFreq(a, 15),
					Tools.SimplifyByFreq(b, 15));
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Freq > 15",  a, b, solution, duration,
					space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic algorithm on simplified problem
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic.lcs(Tools.SimplifyAlea(a, 75),
					Tools.SimplifyAlea(b, 75));
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Alea 75%",  a, b, solution, duration,
					space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic algorithm on simplified problem
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic.lcs(Tools.SimplifyAlea(a, 50),
					Tools.SimplifyAlea(b, 50));
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Alea 50%", a, b, solution, duration,
					space));
		}
		i++;
		if (lcsList[i]) {
			// Dynamic algorithm on simplified problem
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_dynamic.lcs(Tools.SimplifyAlea(a, 25),
					Tools.SimplifyAlea(b, 25));
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Dynamic Alea 25%",  a, b, solution, duration,
					space));
		}
		i++;
		if (lcsList[i]) {
			// Recursion algorithm
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_recursion.lcs(a, b);
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Recursion", a, b, solution, duration, space));
		}
		i++;
		if (lcsList[i]) {
			// branch and bound algorithm
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_branch_and_bound.lcs(a, b);
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Branch and bound", a, b, solution,
					duration, space));
		}
		i++;
		if (lcsList[i]) {
			// divide and conquer algorithm
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_divide_conquer.lcs(a, b);
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("D & C", a, b, solution, duration, space));
		}
		i++;
		if (lcsList[i]) {
			// Greedy algorithm
			thread.reset();
			startTime = System.nanoTime();
			solution = LCS_greedy.lcs(a, b);
			endTime = System.nanoTime();
			duration = endTime - startTime;
			space = thread.getMaxUsedMem();
			results.add(new Result("Greedy", a, b, solution, duration, space));
		}

		// Thread disabling
		thread.run = false;

		return results;

	}

	public static void drawResults(ArrayList<Result> results) {

		String leftAlignFormat = "| %-17s | %-30s | %-30s | %-30s | %-30d | %-30d |%n";

		System.out
				.format("+-------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+%n");
		System.out
				.printf("| Algorithm name    | A                              | B                              | Solution                       | Duration (in ns)               | Max space used                 |%n");
		System.out
				.format("+-------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+%n");

		for (Result r : results) {
			System.out.format(leftAlignFormat, r.getAlgorithm(), r.getA(),
					r.getB(), r.getSolution(), r.getDuration(), r.getSpace());
		}

		System.out
				.format("+-------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+--------------------------------+%n");
	}

	public static void saveResults(ArrayList<Result> results) {
		try {
			FileWriter writer = new FileWriter("out.csv");
			
			

			for (Result r : results) {

				writer.append(r.getAlgorithm());
				writer.append(',');
				writer.append( r.getA());
				writer.append(',');
				writer.append(r.getB());
				writer.append(',');
				writer.append( r.getSolution());
				writer.append(',');
				writer.append(String.valueOf( r.getDuration()));
				writer.append(',');
				writer.append(String.valueOf( r.getSpace()));
				writer.append('\n');
			}

			// generate whatever data you want

			writer.flush();
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public static void drawMenu() {
		String menu = "\n---LCS Algorithm Evaluator---\n";
		menu += "1 - Evaluate with your own strings\n";
		menu += "2 - Evaluate with generated strings (simple) \n";
		menu += "3 - Evaluate with generated strings (growing length)\n";
		menu += "4 - Evaluate with random proteins \n";
		menu += "5 - Evaluate with random english words \n";
		menu += "Choose an action : ";
		System.out.print(menu);
	}

}
